﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Deployment.Application;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Xml;

namespace JBot.Windows {
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class UpdateWindow : Window {
		private WebClient webClient;
		private ObservableCollection<UpdateListItem> updateItemCollection;
		private int CoreId;
		private string UpdateDirPath;
		public UpdateWindow( ) {
			this.webClient = new WebClient( );
			this.webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
			this.webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
			this.updateItemCollection = new ObservableCollection<UpdateListItem>( );
			this.CoreId = -1;
			this.UpdateDirPath = AppInfo.ExecutablePath.DirectoryName + "\\Data\\Update";
			if (ApplicationDeployment.IsNetworkDeployed) {
				ApplicationDeployment.CurrentDeployment.CheckForUpdateCompleted += CurrentDeployment_CheckForUpdateCompleted;
				ApplicationDeployment.CurrentDeployment.CheckForUpdateProgressChanged += CurrentDeployment_CheckForUpdateProgressChanged;
			}
			this.InitializeComponent( );

			this.listViewUpdates.ItemsSource = this.updateItemCollection;
		}

		//Funkcje
		private bool CheckUpdates( ) {
			this.listViewUpdates.IsEnabled = false;
			this.buttonOk.IsEnabled = false;
			this.buttonCheck.IsEnabled = false;
			//Download("http://pytak.no-ip.org/~tbot/math/update/updates.php");
			if (ApplicationDeployment.IsNetworkDeployed)
				ApplicationDeployment.CurrentDeployment.CheckForUpdateAsync( );
			Download("http://update.abstractsoft.eu/jbot/xml.php");
			return true;
		}
		private bool Download(string remoteUrl) {
			this.buttonCheck.IsEnabled = false;
			this.buttonCheck.Content = "0%";
			this.progressBarUpdate.Value = 0;
			if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable( )) {
				//try {
				this.ForceCursor = true;
				this.webClient.DownloadFileAsync(new Uri(remoteUrl), UpdateDirPath + "\\Updates.tmp");
				return true;
				//} catch (Exception) {
				//	this.buttonCheck.Content = "Sprawdź";
				//	this.progressBarUpdate.Value = 0;
				//	switch (MessageBox.Show("Brak połączenia z internetem!\nTwoja sieć lokalna nie ma dostępu do internetu!\nPonowić próbę?", "Brak Połączenia", MessageBoxButton.YesNo, MessageBoxImage.Error)) {
				//		case MessageBoxResult.Yes:
				//			Download(remoteUrl);
				//			break;
				//		default:
				//			this.buttonCheck.IsEnabled = true;
				//			Close( );
				//			break;
				//	}
				//	this.buttonCheck.IsEnabled = true;
				//	return false;
				//}
			} else {
				this.buttonCheck.Content = "Sprawdź";
				this.progressBarUpdate.Value = 0;
				switch (MessageBox.Show("Brak połączenia z internetem!\nNie wykryto jakiego kolwiek połączenia!\nPonowić próbę?", "Brak Połączenia", MessageBoxButton.YesNo, MessageBoxImage.Information)) {
					case MessageBoxResult.Yes:
						Download(remoteUrl);
						break;
					default:
						this.buttonCheck.IsEnabled = true;
						Close( );
						break;
				}
				this.buttonCheck.IsEnabled = true;
				return false;
			}
		}
		private bool CheckFromFile(bool ReadFromCache = false) {
			this.ForceCursor = true;
			this.listViewUpdates.IsEnabled = true;
			if (System.IO.File.Exists(UpdateDirPath + "\\Updates.xml") == true) {
				try {
					System.Xml.XPath.XPathDocument Doc = new System.Xml.XPath.XPathDocument(UpdateDirPath + "\\Updates.xml");
					System.Xml.XPath.XPathNavigator XML = Doc.CreateNavigator( );
					int Group = 0;
					string[ ] Lists = new string[4];
					string[ ] Attributes = new string[5];
					Lists = new string[ ] { "System", "Modules", "Plugins", "Extras" };
					Attributes = new string[ ] { "title", "version", "publishdate", "priority", "href" };
					this.updateItemCollection.Clear( );
					//listViewUpdates.Items.Clear( );
					for (int i = 0; i < Lists.Length; i++) {
						XML.MoveToRoot( );
						XML.MoveToChild("Updates", "");
						XML.MoveToChild(Lists[i], "");
						if (XML.Name == Lists[i]) {
							if (XML.Name == Lists[i]) {
								Group = i;
								XML.MoveToFirstChild( );
							}
							if (XML.Name == "Update") {
								string U_ID = "0";
								do {
									XML.MoveToAttribute("id", "");
									if ((XML.Value != U_ID)) {
										U_ID = XML.Value;
										string[ ] Tab = new string[Attributes.Length];
										for (int j = 0; j < Attributes.Length; j++) {
											XML.MoveToParent( );
											XML.MoveToAttribute(Attributes[j], "");
											Tab[j] = XML.Value;
										}
										if ("" != Tab[4]) {
											Added_Item(Tab[0], Group, Tab[1], Tab[2], Tab[3], Tab[4]);
										}
									} else {
										break;
									}
									XML.MoveToParent( );
									XML.MoveToNext( );
								} while (XML.Name == "Update");
							}
						}
					}
					//ListUpdates.Sorting = SortOrder.Ascending;
					return true;
				} catch (XmlException) {
					if (!ReadFromCache)
						MessageBox.Show("Nie udało się odczytać informacji o aktualizacji.", "Niepowodzenie", MessageBoxButton.OK, MessageBoxImage.Information);
					this.ForceCursor = false;
				}
			}
			return false;
		}
		private bool Install( ) {
			try {
				if (CoreId > -1) {
					if (this.updateItemCollection[CoreId].IsChecked == true) {
					}
				}
				return true;
			} catch (Exception) {
				return false;
			}
		}
		#region Functions for add item to list
		private bool Added_Item(string Name, string Group, string PublishVersion, string PublishDate, string Priority, string File) {
			int group;
			if (int.TryParse(Group, out group))
				return Added_Item(Name, group, PublishVersion, PublishDate, Priority, File);
			else
				return Added_Item(Name, 0, PublishVersion, PublishDate, Priority, File);
		}
		private bool Added_Item(string Name, int Group, string PublishVersion, string PublishDate, string Priority, string File) {
			try {
				int priority = int.Parse(Priority);
				DateTime publishDate = DateTime.Parse(PublishDate);
				Version publishVersion = Version.Parse(PublishVersion);
				return Added_Item(Name, Group, publishVersion, publishDate, priority, File);
			} catch {
				return false;
			}
		}
		private bool Added_Item(string Name, int Group, Version PublishVersion, DateTime PublishDate, int Priority, string File) {
			try {
				this.updateItemCollection.Add(
					new UpdateListItem( ) {
						Name = Name,
						PublishVersion = PublishVersion,
						PublishDate = PublishDate,
						Priority = (UpdatePriorities)Priority,
						File = File
					}
				);
				//this.ListUpdates.Items[IDs].Group = ListUpdates.Groups[Gro];
				return true;
			} catch (Exception) {
				return false;
			}
		}
		#endregion
		#region Event handlers
		private void Window_Loaded(object sender, RoutedEventArgs e) {
			if ((System.IO.Directory.Exists(UpdateDirPath) == false)) {
				System.IO.Directory.CreateDirectory(UpdateDirPath);
			}

			if (System.IO.File.Exists(UpdateDirPath + "\\Updates.xml") == true) {
				CheckFromFile(true);
			}
		}
		private void buttonCheck_Click(object sender, RoutedEventArgs e) {
			CheckUpdates( );
		}
		private void buttonOk_Click(object sender, RoutedEventArgs e) {
			if (Install( ))
				this.Close( );
		}
		private void listViewUpdates_SelectionChanged(object sender, SelectionChangedEventArgs e) {
			if (this.listViewUpdates.SelectedItems.Count > 0) {
				this.buttonOk.IsEnabled = true;
			} else {
				this.buttonOk.IsEnabled = false;
			}
		}
		private void webClient_DownloadProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e) {
			if (!this.buttonCheck.IsSealed) {
				double js = Math.Round(progressBarUpdate.Maximum * e.ProgressPercentage / 100.0);
				this.buttonCheck.Content = e.ProgressPercentage + "%";
				this.progressBarUpdate.Value = (int)js;
			}
		}
		private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
			try {
				if (System.IO.File.Exists(UpdateDirPath + "\\Updates.xml"))
					System.IO.File.Delete(UpdateDirPath + "\\Updates.xml");
				System.IO.File.Copy(UpdateDirPath + "\\Updates.tmp", UpdateDirPath + "\\Updates.xml");
				System.IO.File.Delete(UpdateDirPath + "\\Updates.tmp");
				CheckFromFile( );
			} catch (FileNotFoundException) {
				MessageBox.Show("Procedure of checking updates was failed!", "Failed", MessageBoxButton.OK, MessageBoxImage.Information);
			}
			this.buttonCheck.IsEnabled = true;
			this.ForceCursor = false;
			this.buttonCheck.Content = "Check";
			this.progressBarUpdate.Value = 0;
		}
		private void CurrentDeployment_CheckForUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e) {
			if (!this.buttonCheck.IsSealed) {
				double js = Math.Round(progressBarUpdate.Maximum * e.ProgressPercentage / 100.0);
				this.buttonCheck.Content = e.ProgressPercentage + "%";
				this.progressBarUpdate.Value = (int)js;
			}
		}
		private void CurrentDeployment_CheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e) {
			try {
				if (ApplicationDeployment.CurrentDeployment.CurrentVersion < ApplicationDeployment.CurrentDeployment.UpdatedVersion) {
					string AppVer = ApplicationDeployment.CurrentDeployment.UpdatedVersion.Major + "." + ApplicationDeployment.CurrentDeployment.UpdatedVersion.Minor + "." + ApplicationDeployment.CurrentDeployment.UpdatedVersion.Build;
					string AppScr = ApplicationDeployment.CurrentDeployment.UpdateLocation.AbsolutePath;
					Added_Item("Core Update", 0, AppVer, "Tooday", "3", AppScr);
				}
				//ListUpdates.Sorting = SortOrder.Ascending;
				this.ForceCursor = false;
			} catch (Exception ex) {
				MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
				this.ForceCursor = false;
			}
		}
		#endregion
	}
	#region Helper class
	public class UpdateListItem {
		public bool IsChecked {
			get;
			set;
		}
		public string Name {
			get;
			set;
		}
		public Version PublishVersion {
			get;
			set;
		}
		public DateTime PublishDate {
			get;
			set;
		}
		public UpdatePriorities Priority {
			get;
			set;
		}
		public string File {
			get;
			set;
		}
	}
	#endregion
	#region Helper enum
	public enum UpdatePriorities : int {
		Critical = 0,
		Important = 1,
		Suggested = 2,
		Optional = 3,
	}
	#endregion
}